
#include <BStyle>
#include <BPainter>
#include <BRender>
#include <BViewer>
#include <BScene>
#include <BCone>
#include <BCube>
#include <BImage>
#include <BMaterial>
#include <BReadWrite>

#include <BFixedRestraint>
#include "SliderHandler.h"

SliderHandler::SliderHandler()
{
	_group = new BGroup();

	_lengthText = new BTextual();
	_lengthText->setColor(200, 0, 0);
	_lengthText->setCullback(false);
	_lengthText->setLighting(false);
	_lengthText->setPolyMode(Poly_Fill);
	_lengthText->setGlyphSize((BReal)0.3);
	_group->insert(_lengthText);

	_nodeA = new BBody("nodeA");
	{
		_nodeA->setMass(0);
		_nodeA->setGravity(0, 0, -10);
		_nodeA->move(0, 0, 0.8);

		BCube* cube = new BCube(0.4, 12);
		cube->setColor(100, 200, 255);
		_nodeA->insertShape(cube);
		_group->insert(_nodeA);
	}

	_nodeB = new BBody("nodeB");
	{
		_nodeB->setMass(1);
		_nodeB->setGravity(0, 0, -10);

		BCone* cone = new BCone(0.1, 0.2, 24, 10);
		cone->setColor(200, 100, 0);
		cone->setPolySmooth(true);
		_nodeB->insertShape(cone);
		_group->insert(_nodeB);
	}

	_nodeC = new BBody("nodeC");
	{
		_nodeC->setMass(1);
		_nodeC->setGravity(0, 0, -10);

		BCube* cube = new BCube(0.1, 0.1, 1, 12);
		cube->setColor(100, 200, 255);
		_nodeC->insertShape(cube);
		_group->insert(_nodeC);
	}

	{
		const BSpace& spaceA = _nodeA->space();
		BVector pointA(0, 0, spaceA.depth() / 2);
		BVector axisA(0, 0, 1);
		BVector pointB(0, 0, -0.5);
		BVector axisB(0, 0, 1);
		_fixedRestraint = new BFixedRestraint(_nodeA, pointA, _nodeB, pointB);
		_fixedRestraint->setRotation(0, 0, PI / 4);
		_group->insert(_fixedRestraint);
	}

	{
		BSliderRestraint* sliderRestraint = new BSliderRestraint(_nodeA, _nodeC);
		sliderRestraint->setPivotA(0.5, _nodeA->space().height() / 2, _nodeA->space().depth() / 2);
		sliderRestraint->setPivotB(0, 0, 0.1);
		sliderRestraint->setAxisA(0, 0, 1);
		sliderRestraint->setAxisB(0, 0, 1);
		sliderRestraint->setLinearLimit(0, 1);
		sliderRestraint->setAngularLimit(0, 0);
		sliderRestraint->setColliding(true);
		_group->insert(sliderRestraint);
		_sliderRestraint = sliderRestraint;
	}
}
SliderHandler::~SliderHandler()
{

}

void SliderHandler::attached(BViewer* viewer)
{
	BScene* dscene = viewer->scene();
	dscene->insert(_group);
	_lengthText->setFont((BFont*)viewer->realFont());
	this->emit("edit-restraint", _sliderRestraint);
}
void SliderHandler::detached(BViewer* viewer)
{
	BScene* dscene = viewer->scene();
	dscene->remove(_group);
}

void SliderHandler::paint(BPainter& painter)
{
	BViewer* viewer = this->viewer();

}
void SliderHandler::render(BRender& render)
{
	render.setLighting(false);
	render.setDepthTest(false);
	render.setLineSmooth(true);
	render.setLineWidth(1);

	if (_fixedRestraint)
	{
		const BVector& center = _fixedRestraint->property("center");
		render.setColor(255, 0, 0);
		render.setPointSize(10);
		render.drawVertex(center);

		const BBox& box = _fixedRestraint->property("box");
		render.setColor(0, 255, 255);
		render.drawBox(box);
	}
	if (_sliderRestraint)
	{
		render.setColor(255, 255, 255);
		render.drawLine(_axisLine);

		BQuad quad = _lengthText->quad() * _lengthText->matrix();
		render.drawQuad(quad);

		BVector vp, vq;
		PlaneSpace(_axisLine.direct(), vp, vq);
		BVector offset = vp * 2;
		BVector pointB = _sliderRestraint->pivotB() * _sliderRestraint->bodyB()->matrix();
		BVector leftCenter = (quad.a() + quad.b()) / 2;
		BVector rightCenter = (quad.c() + quad.d()) / 2;
		BVector pointA0 = _axisLine.begin() + offset;
		BVector pointB0 = pointB + offset;
		render.setLineWidth(1);
		render.setLineStipple(0xF0F0);
		render.setColor(255, 255, 255);
		render.drawLine(_axisLine.begin(), pointA0);
		render.drawLine(pointA0, leftCenter);
		render.drawLine(pointB, pointB0);
		render.drawLine(pointB0, rightCenter);
		render.setLineStipple(0x0000);
	}

}

void SliderHandler::styleEvent(const BEvent& event)
{
	BHandler::styleEvent(event);
	const BStyle* style = event.value();
	BImage* image = style->image("cone-texture");
	if (BShape* shape = _nodeB->shape(0))
	{
		shape->setTexture(image);
	}
}
void SliderHandler::freshEvent(const BEvent& event)
{
	BHandler::freshEvent(event);

	const BMatrix& matrixA = _sliderRestraint->bodyA()->matrix();
	const BRealRange& linearLimit = _sliderRestraint->linearLimit();
	_axisLine.setBegin((_sliderRestraint->pivotA() + _sliderRestraint->axisA() * linearLimit.min()) * matrixA);
	_axisLine.setEnd((_sliderRestraint->pivotA() + _sliderRestraint->axisA() * linearLimit.max()) * matrixA);

	BVector pointB = _sliderRestraint->pivotB() * _sliderRestraint->bodyB()->matrix();
	BVector vp, vq;
	PlaneSpace(_axisLine.direct(), vp, vq);
	BVector offset = vp * 2;
	BReal length = _axisLine.ratio(pointB);
	BString lengthStr(length, 3);
	_lengthText->setText(lengthStr);
	_lengthText->setDown(vp);
	_lengthText->setRight(_axisLine.direct());
	_lengthText->setPosition((_axisLine.begin() + pointB) / 2 + offset);
}
